/**
 * Class representing some common statistical functions
 */
package common;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.math.stat.StatUtils;
import org.apache.commons.math.stat.regression.SimpleRegression;

/**
 * @author vladimir
 * 
 */
public class Stat {

	public static double mean(Double[] tM) {
		double result = 0;
		for (double element : tM) {
			result += element;
		}
		return result / tM.length;
	}

	public static double mean(Integer[] input) {

		double[] temp = new double[input.length];
		for (int i = 0; i < input.length; i++) {
			temp[i] = input[i];
		}

		return StatUtils.mean(temp);
	}

	public static double variance(double[] input) {
		double[] i2 = new double[input.length];
		for (int i = 0; i < input.length; i++) {
			i2[i] = Math.pow(input[i], 2);
		}
		return StatUtils.mean(i2) - Math.pow(StatUtils.mean(input), 2);
	}

	public static double min(double[] input) {
		double result = input[0];
		for (int i = 1; i < input.length; i++) {
			if (result < input[i]) {
				result = input[i];
			}
		}
		return result;
	}

	/*
	 * Function analyzes array of suoble and returns correlation length, meaning
	 * fow far apart we can consider values independent
	 */
	public static double[] corLenArray(Double[] input) {
		double mI = mean(input);

		int N = input.length;
		// substruct mean from each value
		for (int i = 0; i < input.length; i++) {
			input[i] -= mI;
		}

		int maxCorLength = 200;// Later I should change this black magic number
								// to something more appropriate
		double[] data = new double[maxCorLength];

		for (int l = 0; l < maxCorLength; l++) {
			double tc = 0;
			for (int i = 1; i <= N - l; i++) {
				tc += input[i - 1] * input[i + l - 1];
			}

			data[l] = tc / (N - l);
		}
		double norm = data[0];
		for (int i = 0; i < data.length; i++) {
			data[i] /= norm;
		}

		// At this moment we have some array with decaying exponent. I don't
		// know whay but it's tail looks bad.
		// I'll cut everything less then 0.05 I agree it is another magic number
		// but that is life.
		List<Double> result = new ArrayList<Double>();

		for (double dt : data) {
			if (dt > 0.05) {
				result.add(dt);
			}
		}

		double[] result1 = new double[result.size()];

		for (int i = 0; i < result.size(); i++) {
			result1[i] = result.get(i);
		}

		return result1;
	}

	public static int corLen(Double[] input) {
		// /*
		// * Our data should be approximated by C * exp ( - l / Tau) => if we
		// plot
		// * ln(our points) vs ln( C * exp ( - l / Tau) ) slope will be (
		// -1/tau)
		// */
		double[] data = corLenArray(input);
		SimpleRegression regression = new SimpleRegression();

		for (int l = 0; l < data.length; l++) {
			// System.out.println("point: " + Math.log(data[l]));

			regression.addData(l, Math.log(data[l]));
		}
		int result = Math.max((int) (-1 / regression.getSlope()), 1);
		return result;
	}
}
